package cc.shacocloud.mirage.restful.bind.validation;

import cc.shacocloud.mirage.utils.Utils;
import cc.shacocloud.mirage.utils.converter.TypeConverter;
import cc.shacocloud.mirage.utils.converter.TypeDescriptor;
import cc.shacocloud.mirage.utils.converter.TypeMismatchException;
import jakarta.validation.ConstraintViolation;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.Nullable;

import java.util.Objects;
import java.util.Set;


/**
 * 允许在目标对象上设置属性值的绑定程序，包括对验证和绑定结果分析的支持
 */
@Slf4j
public class DataBinder implements TypeConverter {
    
    /**
     * 用于绑定的默认对象名称
     */
    public static final String DEFAULT_OBJECT_NAME = "target";
    
    @Getter
    @Setter
    @Nullable
    private Object target;
    
    @Getter
    private final String objectName;
    
    @Setter
    @Nullable
    private SmartValidator validator;
    
    @Getter
    @Nullable
    private BindingResult bindingResult;
    
    @Setter
    private TypeConverter typeConverter;
    
    /**
     * 使用默认对象名称创建新的数据绑定程序实例
     *
     * @param target 要绑定到的目标对象（如果绑定程序仅用于转换纯参数值，则为 {@code null}）
     * @see #DEFAULT_OBJECT_NAME
     */
    public DataBinder(@Nullable Object target) {
        this(target, DEFAULT_OBJECT_NAME);
    }
    
    /**
     * 创建新的数据绑定程序实例。
     *
     * @param target     要绑定到的目标对象（如果绑定程序仅用于转换纯参数值，则为 {@code null}）
     * @param objectName 目标对象的名称
     */
    public DataBinder(@Nullable Object target, String objectName) {
        this.target = Utils.unwrapOptional(target);
        this.objectName = objectName;
    }
    
    /**
     * 使用给定的验证提示调用指定的验证程序（如果有）
     * <p>
     * 注意：实际目标验证器可能会忽略验证提示
     *
     * @see #validator
     * @see SmartValidator#validate(Object, Class[])
     */
    public void validate(Class<?>[] hints) {
        if (Objects.nonNull(validator) && Objects.nonNull(target)) {
            Set<ConstraintViolation<Object>> constraintViolations = validator.validate(target, hints);
            this.bindingResult = new ConstraintViolationBindingResult(target, constraintViolations);
        }
    }
    
    /**
     * 数据验证是否存在错误
     * <p>
     * 必须在 {@link #validate} 之后执行
     */
    public boolean hasErrors() {
        return Objects.nonNull(bindingResult) && bindingResult.hasErrors();
    }
    
    @Override
    public <T> @Nullable T convertIfNecessary(@Nullable Object source,
                                              @Nullable Class<T> requiredType,
                                              @Nullable TypeDescriptor typeDescriptor) throws TypeMismatchException {
        if (Objects.isNull(typeConverter)) {
            throw new IllegalStateException("未设置 TypeConverterSupport");
        }
        return typeConverter.convertIfNecessary(source, requiredType, typeDescriptor);
    }
    
}
